#include "DynamicShellParser.h"
#include <sstream>
#include <string.h>
#include <iostream>
#include <stdio.h>
#include "../utils/Functions.h"
#include "Parser.h"
#include "../utils/Constantes.h"
#include "../query/Query.h"

using std::string;
using std::stringstream;
using std::cin;
using std::cout;
using std::endl;
using namespace convertTypes;

DynamicShellParser::DynamicShellParser() {
	cache = new Cache();
}

DynamicShellParser::DynamicShellParser(string repo) {
	cache = new Cache();
	this->repo = repo;
}


DynamicShellParser::~DynamicShellParser() {
	delete cache;
}

void DynamicShellParser::run() {
	clock_t chrono = clock();
	string input = string("");
	printf("Bienvenido al modo dinámico y veloz de búsqueda.\n");
	printf("  Recuerde que para salir debe ingresar 0 y presionar enter\n\n");
	getline(cin, input);

	TermYFrecQuery* temp;
	Parser* parser = new Parser();
	Query* q = new Query(repo);

	while (input.length() != 1 || input.at(0) != '0') {

		if (!input.empty()) {

			vector<QueryToken> * query = parser->parseQuery(input.c_str());
			for (unsigned int i = 0; i < query->size(); i++) {
				temp = cache->search(query->at(i).word);
				if(temp == NULL){//Si el termino no estaba en la cache, busco sus datos en el indice.
					query->at(i).v_data = q->busquedaBinaria(query->at(i).word);
					if( this->cache->getBuscados()->getSize() >= TAMANIO_MAXIMO_CACHE) {
						cache->eliminateLeastFrequent();
					}

					// creo un nuevo query token para que sea distinto el de la cache.
					QueryToken* vAux = new QueryToken(query->at(i));
					for(unsigned int j=0; j<vAux->v_data->size(); j++) {
						vAux->v_data = new vector<Data>(*(vAux->v_data));
						for(unsigned int k=0; k<vAux->v_data->size(); k++) {
							vAux->v_data->at(k).pos = new vector<unsigned int> (*(vAux->v_data->at(k).pos));
						}
					}
					cache->insert(*(vAux));
				} else {//estaba en la cache

					// creo un nuevo vector de data (distinto al de la cache).
					vector<Data>* aux = new vector<Data>(*(temp->datosTermino));
					for(unsigned int j=0; j<aux->size(); j++) {
						aux->at(j).pos = new vector<unsigned int>(*(aux->at(j).pos));
					}
					query->at(i).v_data = aux;
				}
			}

			vector<Match>* matchs = q->resolveQuery(query);
			vector<unsigned int> * result = new vector<unsigned int>();
			//matchs puede venir vacio en el caso en que una de las palabras no este en ningun documento
			if (matchs->size()!= 0){
				qsort ((void*)&(matchs->at(0)), matchs->size(), sizeof(Match), cmp_match); //ordeno los matchs por la longitud de match
//				for (unsigned int i=0; i<matchs->size(); i++){
//					result->push_back(matchs->at(i).document);
//				}
				printTimeToFindNResults(chrono, matchs->size());
//				q->printDocumentsNames(result);
				q->printDocumentsNames(matchs);
			} else {
				printNoResultsFound();
			}

			if (DEBUG > 1)
				cache->printCache();
			delete result;
			query->clear();
			delete query;
			matchs->clear();
			delete matchs;
			cout << endl << "Ingrese la siguiente consulta que desea realizar o ingrese \"0\" para salir." << endl << endl;
		}

		getline(cin, input);
		if(!input.empty() && DEBUG > 1)
			cout << "  Input: " << input << endl;
		chrono = clock();
	}
	delete q;
//	if(query != NULL)
//		delete query;
	delete parser;
}
